#pragma once
#include <iostream>
#include <memory>

#include "jsoncpp/json/json.h"

namespace Protocol
{
    const std::string ProtSep = " ";
    const std::string LineBreakSep = "\n";

    // 添加报头
    // 未来传入的是一个"_data_x op _data_y"
    // 我们需要添加成这样"len\n_data_x op _data_y\n"
    std::string Encode(const std::string &message)
    {
        std::string len = std::to_string(message.size());
        std::string package = len + LineBreakSep + message + LineBreakSep;
        return package;
    }

    // 去除报头
    // 未来传入的是一"len\n_data_x op _data_y\n"
    // 我们需要去掉报头转化为"_data_x op _data_y"
    /*********************************************
     * 由于TCP协议的缘故，这里解析报头时需要注意的是
     * 我们不确定传入的package是否是一个完整的报文
     * 很有可能是下面这种报文不完整或者多出来的的情况
     * "len
     * "len\n"
     * "len\n_data_x
     * "len\n_data_x op
     * "len\n_data_x op _data_y
     * "len\n_data_x op _data_y\n"
     * "len\n_data_x op _data_y\n""len
     * "len\n_data_x op _data_y\n""len\n
     * "len\n_data_x op _data_y\n""len\n_data_x
     * "len\n_data_x op _data_y\n""len\n_data_x op
     * "len\n_data_x op _data_y\n""len\n_data_x op _data_y
     * "len\n_data_x op _data_y\n""len\n_data_x op _data_y\n"
     * 要不缺少要不多出来，这里就需要特殊处理了
     *********************************************/
    bool Decode(std::string &package, std::string *message)
    {
        // 先找到能确定报头与有效载荷的\n
        auto pos = package.find(LineBreakSep);
        if (pos == std::string::npos)
            return false;

        // 确定有效载荷的长度
        std::string lens = package.substr(0, pos);
        int messagelen = std::stoi(lens);
        // 确定整个报文的总长度
        int total = lens.size() + messagelen + 2 * LineBreakSep.size();
        // package的总长度一定要大于或者等于total，这样才至少会有一个完成的报文
        if (package.size() < total)
            return false;
        // 走到这里就一定至少有一个完整的报文
        // 截取完整报文有效载荷的信息
        *message = package.substr(pos + LineBreakSep.size(), messagelen);
        // 截取成功后将已经获取到的报文丢弃掉
        package.erase(0, total);
        return true;
    }

    class Request
    {
    public:
        Request() {}
        Request(int x, int y, char op)
            : _data_x(x), _data_y(y), _oper(op)
        {
        }

        // 对结构化字段转化为字符串
        // 转化成这种类型"_data_x op _data_y"
        bool Serialize(std::string *out)
        {
#ifdef SelfDefine
            std::string temp = std::to_string(_data_x);
            temp += ProtSep;
            temp += _oper;
            temp += ProtSep;
            temp += std::to_string(_data_y);
            *out = temp;

            return true;
#else
            Json::Value root;
            root["datax"] = _data_x;
            root["datay"] = _data_y;
            root["oper"] = _oper;
            Json::FastWriter writer;
            *out = writer.write(root);
            return true;
#endif
        }
        // 将字符串转化为结构化字段
        // 未来传入的字符串类型"_data_x op _data_y"
        bool Deserialize(std::string &in)
        {
#ifdef SelfDefine
            auto left = in.find(ProtSep);
            if (left == std::string::npos)
                return false;
            auto right = in.rfind(ProtSep);
            if (right == std::string::npos)
                return false;
            _data_x = std::stoi(in.substr(0, left));
            _data_y = std::stoi(in.substr(right + ProtSep.size()));
            std::string oper = in.substr(left + ProtSep.size(), right - (left + ProtSep.size()));
            if (oper.size() != 1)
                return false;
            _oper = oper[0];

            return true;
#else
            Json::Value root;
            Json::Reader reader;
            bool res = reader.parse(in, root);
            if (res)
            {
                _data_x = root["datax"].asInt();
                _data_y = root["datay"].asInt();
                _oper = root["oper"].asInt();
            }
            return res;
#endif
        }

        void Debug()
        {
            std::cout << "_data_x: " << _data_x << std::endl;
            std::cout << "_data_y: " << _data_y << std::endl;
            std::cout << "_oper: " << _oper << std::endl;
        }
        void Inc()
        {
            _data_x++;
            _data_y++;
        }
        int GetX() { return _data_x; }
        int GetY() { return _data_y; }
        char GetOper() { return _oper; }

    private:
        // _data_x oper _data_y
        int _data_x; // 参数1
        int _data_y; // 参数2
        char _oper;  // 运算符号
    };

    class Response
    {
    public:
        Response() {}
        Response(int result, int code)
            : _result(result), _code(code)
        {
        }
        // 对结构化字段转化为字符串
        // "_result _code"
        bool Serialize(std::string *out)
        {
#ifdef SelfDefine
            std::string temp = std::to_string(_result);
            temp += ProtSep;
            temp += std::to_string(_code);
            *out = temp;

            return true;
#else
            Json::Value root;
            root["result"] = _result;
            root["code"] = _code;
            Json::FastWriter writer;
            *out = writer.write(root);
            return true;
#endif
        }
        // 将字符串转化为结构化字段
        // 未来传入的字符串类型"_result _code"
        bool Deserialize(std::string &in)
        {
#ifdef SelfDefine
            auto pos = in.find(ProtSep);
            if (pos == std::string::npos)
                return false;
            _result = std::stoi(in.substr(0, pos));
            _code = std::stoi(in.substr(pos + ProtSep.size()));

            return true;
#else
            Json::Value root;
            Json::Reader reader;
            bool res = reader.parse(in, root);
            if (res)
            {
                _result = root["result"].asInt();
                _code = root["code"].asInt();
            }
            return res;
#endif
        }
        void SetResult(int result) { _result = result; }
        void SetCode(int code) { _code = code; }
        int GetResult() { return _result; }
        int GetCode() { return _code; }

    private:
        int _result; // 运算结果
        int _code;   // 运算状态
    };

    // 建造类设置模式：工厂模式
    class Factory
    {
    public:
        std::shared_ptr<Request> BuildRequest()
        {
            std::shared_ptr<Request> req = std::make_shared<Request>();
            return req;
        }
        std::shared_ptr<Request> BuildRequest(int x, int y, char op)
        {
            std::shared_ptr<Request> req = std::make_shared<Request>(x, y, op);
            return req;
        }
        std::shared_ptr<Response> BuildResponse()
        {
            std::shared_ptr<Response> resp = std::make_shared<Response>();
            return resp;
        }
        std::shared_ptr<Response> BuildResponse(int result, int code)
        {
            std::shared_ptr<Response> resp = std::make_shared<Response>(result, code);
            return resp;
        }
    };
}